/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package filmlibrary.orm;

import filmlibrary.orm.classes.Comments;
import filmlibrary.orm.classes.CommentsId;
import filmlibrary.orm.classes.Films;
import filmlibrary.orm.classes.Genres;
import filmlibrary.orm.classes.Groups;
import filmlibrary.orm.classes.Quality;
import filmlibrary.orm.classes.Users;
import filmlibrary.web.LanguageSwitcher;
import filmlibrary.web.SearchBean;

import java.sql.Date;
import java.util.ArrayList;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author karol
 */
public class ORMHelper {

    Session session = null;
    private static final Logger logger = Logger.getLogger(ORMHelper.class.getName());

    public ORMHelper() {
        logger.info("ORMHEelper constructor");
        //if(HibernateUtil.getSessionFactory().isClosed())//if there is no session start one
        this.session = HibernateUtil.getSessionFactory().openSession();
        //else //else get current session
        //  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
    }

    public void close() {
        this.session.close();
    }

    public void deleteFilm(int id) {
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("delete from Films where idfilms=:id");
            query.setParameter("id", id);
            int i = query.executeUpdate();
            tx.commit();
            logger.info("usunieto wierszy: " + i);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    /** Returns a list of Films that is a result of an user search */
    public List<Films> getSearchResult(SearchBean sb) {

        List<Object> ob = new ArrayList();//list of query's parameters' objects
        List<String> desc = new ArrayList();//list of querry's parameters' descriptions
        List<Films> f = new ArrayList();//query's result's list
        String[] garray = null;//array for genres
        String garrayName = "genres";
        String q;// the beginning of a query
        if (sb.getGenre().length > 0) {
            q = "select f from Films as f join f.genreses as g where";
        } else {
            q = "select f from Films as f where";
        }
        boolean isFirst = true; // check if it's first part of a quary - the one without AND

        if (!sb.getFilmName().isEmpty()) {
            if (isFirst == true) {
                q += " f.titleOrg=:titleOrg";
                isFirst = false;
            } else {
                q += " AND f.titleOrg=:titleOrg";
            }
            ob.add(sb.getFilmName());
            desc.add("titleOrg");
        }
        if (sb.getUser() != null) {
            logger.info("user search for user: " + sb.getUser());
            if (isFirst == true) {
                q += " f.users.username=:user";
                isFirst = false;
            } else {
                q += " AND f.users.username=:user";
            }
            ob.add(sb.getUser());
            desc.add("user");
        }
        if (sb.getQuality() != null) {
            if (isFirst == true) {
                q += " f.quality.name=:quality";
                isFirst = false;
            } else {
                q += " AND f.quality.name=:quality";
            }
            ob.add(sb.getQuality());
            desc.add("quality");
        }
        if (sb.getSizeTo() != 0) {
            if (isFirst == true) {
                q += " f.fileSize>=:sizeFrom AND f.fileSize<=:sizeTo";
                isFirst = false;
            } else {
                q += " AND f.fileSize>=:sizeFrom AND f.fileSize<=:sizeTo";
            }
            ob.add(sb.getSizeFrom());
            desc.add("sizeFrom");
            ob.add(sb.getSizeTo());
            desc.add("sizeTo");
        }
        if (sb.getYearFrom() != 0) {
            if (isFirst == true) {
                q += " f.year>=:yearFrom";
                isFirst = false;
            } else {
                q += " AND f.year>=:yearFrom";
            }
            ob.add(sb.getYearFrom());
            desc.add("yearFrom");
        }
        if (sb.getYearTo() != 0) {
            if (isFirst == true) {
                q += " f.year<=:yearTo";
                isFirst = false;
            } else {
                q += " AND f.year<=:yearTo";
            }
            ob.add(sb.getYearTo());
            desc.add("yearTo");
        }
        if (sb.getRankFrom() != 0) {
//            if (isFirst == true) {
//                q += "";
//                isFirst = false;
//            } else {
//                q += "";
//            }
            //ob.add(sb.getRankFrom());
            //desc.add("rankFrom");
        }
        if (sb.getRankTo() != 0) {
//            if (isFirst == true) {
//                q += " f.";
//                isFirst = false;
//            } else {
//                q += " AND f.";
//            }
//            ob.add(sb.getRankTo());
//            desc.add("rankTo");
        }
        if (sb.getGenre().length > 0) {
            logger.info("Genres search");
            if (isFirst == true) {
                q += " g.nameEn in (:genres) OR g.namePl in (:genres) group by f having count(g)>=:genreCount";
                isFirst = false;
            } else {
                q += " AND (g.nameEn in (:genres) OR g.namePl in (:genres)) group by f having count(g)>=:genreCount";
            }
            garray = sb.getGenre();
            garrayName = "genres";
            ob.add((long) sb.getGenre().length);
            desc.add("genreCount");
        }
        if (isFirst == false) {//if there are any data for a query
            Query query = session.createQuery(q);
            logger.info(q);
            for (int i = 0; i < ob.size(); ++i) {
                query.setParameter(desc.get(i), ob.get(i));
            }
            if (garray != null) {
                query.setParameterList(garrayName, garray);
            }
            f = query.list();
        }

        logger.info(f.toString());
        for (int i = 0; i < f.size(); ++i) {
            logger.info(f.get(i).getTitleOrg());
        }

        return f;
    }

    public Integer[] getMaxMinYear() {
        Integer[] yearSpan = new Integer[2];

        List<Integer> mm = null;
        int max, min;
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("select min(f.year), max(f.year) from Films as f");
            query.setMaxResults(1);//setting max result to 1 to be sure to get only one row
            Object[] objects = (Object[]) query.uniqueResult();
            yearSpan[0] = (Integer) objects[0];
            yearSpan[1] = (Integer) objects[1];


        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("minimum: " + yearSpan[0] + "  max" + yearSpan[1]);
        return yearSpan;
    }

    public List<Users> getUsers2() {//for admin pages
        List<Users> u = null;
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("from Users as u");
            u = query.list();
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("Number of users: " + u.size());
        return u;
    }

    public List<String> getUsers() {
        List<String> u = null;
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("select u.username from Users as u");
            u = query.list();
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info("Number of users: " + u.size());
        return u;
    }

    public Films getFilmbyId(int filmId) {

        Films f = null;
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("from Films as f where f.idfilms=:filmId");
            query.setMaxResults(1);//setting max result to 1 to be sure to get only one row

            query.setParameter("filmId", filmId);
            f = (Films) query.uniqueResult();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }

    public Genres getGenrebyName(String genreName) {
        Genres g = null;
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("from Genres as g where g.nameEn=:gn or g.namePl=:gn");
            query.setMaxResults(1);//setting max result to 1 to be sure to get only one row
            query.setParameter("gn", genreName);
            g = (Genres) query.uniqueResult();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return g;
    }

    public Quality getQualitybyName(String qualityName) {
        Quality q = null;
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("from Quality as q where q.name=:qn");
            query.setMaxResults(1);//setting max result to 1 to be sure to get only one row
            query.setParameter("qn", qualityName);
            q = (Quality) query.uniqueResult();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return q;
    }

    public Users getUserbyName(String user) {
        Users u = null;
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("from Users as u where u.username=:username");
            query.setMaxResults(1);//setting max result to 1 to be sure to get only one row
            query.setParameter("username", user);
            u = (Users) query.uniqueResult();
        } catch (Exception e) {
            e.printStackTrace();
        }


        return u;
    }

    public List<Quality> getQualities() {
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Quality name");
        List<Quality> q = query.list();
        return q;
    }

    public List<Genres> getGenres() {
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Genres nameEn");
        List<Genres> genresNames = query.list();
        return genresNames;
    }

    public List<Films> getUserFilms(String user) {
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Films as f where f.users.username=:user");
        query.setParameter("user", user);
        List<Films> films = query.list();
        return films;
    }

    public void updateFilm(Films film, String[] genre, String quality, int id) {
        logger.info("id " + id);
        try {
            Query query;
            Transaction tx = session.beginTransaction();
            if (FacesContext.getCurrentInstance().getViewRoot().getLocale().getLanguage() == "en") {
                query = session.createQuery("from Genres g where g.nameEn in (:genres)");
            } else {
                query = session.createQuery("from Genres g where g.namePl in (:genres)");
            }

            query.setParameterList("genres", genre);
            Set<Genres> sg = new HashSet(query.list());
            logger.info("ilość genres: " + sg.size());
            query = session.createQuery("from Quality q where q.name=:quality");

            query.setParameter("quality", quality);
            Quality q = (Quality) query.uniqueResult();
            query = session.createQuery("from Films f where f.idfilms=:id");

            query.setParameter("id", id);
            Films f = (Films) query.uniqueResult();
            logger.info("quality: " + q.getName());
            logger.info("user" + film.getTitleEn());
            f.setTitleOrg(film.getTitleOrg());
            f.setTitleEn(film.getTitleEn());
            f.setTitlePl(film.getTitlePl());
            f.setFileSize(film.getFileSize());
            f.setYear(film.getYear());
            f.setQuality(q);
            f.setGenreses(sg);
            session.merge(f);
            tx.commit();

        } catch (Exception e) {
            e.printStackTrace();


        }
    }

    public void addFilm(String login, String quality, String titleOrg, String titleEn, String titlePl, short year, int fileSize, String[] genre) {
        Users u = this.getUserbyName(login);
        Quality q = this.getQualitybyName(quality);
        Set<Genres> sg = new HashSet<Genres>(0);


        for (int i = 0; i
                < genre.length;
                ++i) {
            sg.add(this.getGenrebyName(genre[i]));


        }
        Transaction tx = session.beginTransaction();
        Films f = new Films(u, q, titleOrg, titleEn, titlePl, (int) year, fileSize, new Date(new java.util.Date().getTime()), sg);
        session.save(f);
        tx.commit();


    }

    public void addComment(String login, Films film, String content) {
        Transaction tx = session.beginTransaction();
        Users u = getUserbyName(login);
        CommentsId id = new CommentsId(film.getIdfilms(), u.getIdusers());
        Comments c = new Comments(id, u, film, content, new Date(new java.util.Date().getTime()));
        session.save(c);
        tx.commit();


    }

    public List<Films> getFilms() {
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Films as f");
        List<Films> films = query.list();


        return films;

    }

    public void updateUser(Users user) {
        try {
            Transaction tx = session.beginTransaction();
            Users u = user;
            logger.info("update User: " + user.getUsername());
            session.update(user);
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();


        }
    }

    public Users getUserbyId(int id) {
        Users u = null;
        try {
            Transaction tx = session.beginTransaction();
            Query query = session.createQuery("from Users as u where u.idusers=:userid");
            query.setMaxResults(1);//setting max result to 1 to be sure to get only one row
            query.setParameter("userid", id);
            u = (Users) query.uniqueResult();
        } catch (Exception e) {
            e.printStackTrace();
        }


        return u;
    }

    public void addUser(Users user) {

        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Groups where groupName='USER'");
        Groups g = (Groups) query.uniqueResult();
        Set<Groups> sg = new HashSet<Groups>();
        sg.add(g);
        user.setGroupses(sg);
        session.save(user);
        tx.commit();


    }

    public void deleteUser(int id) {
        logger.info("user id: " + id);
        Query query = null;
        try {
            Transaction tx = session.beginTransaction();
            query = session.createQuery("select idfilms from Films where users.idusers=:id");
            query.setParameter("id", id);
            List<Integer> lf = query.list();
            for(Integer i : lf){
                deleteFilm(i);
            }

            query = session.createQuery("delete from Users where idusers=:id");
            query.setParameter("id", id);
            int i = query.executeUpdate();
            tx.commit();
            logger.info("usunieto użytkowników: " + i);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}
